package com.iflytek.cosmo.ocr.support.license;

import javax.crypto.Cipher;
import java.io.IOException;
import java.io.InputStream;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.codec.Base64Encoder;
import org.springframework.core.io.ClassPathResource;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2021/6/29
 */
public abstract class LicenseProcessor {

    protected static final String CERT_TYPE = "X.509";

    private static X509Certificate certificate = null;
    private static PublicKey publicKey = null;

    static {
        try {
            try (InputStream inputStream = getCertificateFile()) {
                certificate = getCertificateByCertPath(inputStream, CERT_TYPE);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        publicKey = getPublicKey(certificate);
    }

    /** 获取支持的版本 */
    public abstract LicenseVersion supportVersion();

    protected static InputStream getCertificateFile() throws IOException {
        // 本地开发调用
        ClassPathResource resource = new ClassPathResource("viewOcrCertificate.cer");
        return resource.getInputStream();
    }

    /**
     * 验签，公钥包含在证书里面
     *
     * @param decodedText
     * @param receivedignature
     *
     * @return
     */
    public boolean verify(byte[] decodedText, final byte[] receivedignature) throws Exception {
        Signature signature = Signature.getInstance(certificate.getSigAlgName());
        /** 注意这里用到的是证书，实际上用到的也是证书里面的公钥 */
        signature.initVerify(certificate);
        signature.update(decodedText);
        return signature.verify(receivedignature);
    }

    /**
     * 获取公钥
     *
     * @param certificate
     *
     * @return
     */
    protected static PublicKey getPublicKey(Certificate certificate) {
        return certificate.getPublicKey();
    }

    /**
     * 通过证书路径生成证书，与加载密钥库差不多，都要用到流。
     *
     * @param certInputStream
     * @param certType
     *
     * @return
     *
     * @throws IOException
     */
    protected static X509Certificate getCertificateByCertPath(InputStream certInputStream, String certType) throws Exception {
        // 实例化证书工厂
        CertificateFactory factory = CertificateFactory.getInstance(certType);
        // 生成证书
        Certificate certificate = factory.generateCertificate(certInputStream);

        return (X509Certificate) certificate;
    }

    /**
     * 解密，注意密钥是可以获取它适用的算法的。
     *
     * @param encodedText
     *
     * @return
     */
    protected static byte[] decrypt(byte[] encodedText) throws Exception {
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(encodedText);
    }

    protected static String base64Encode(byte[] bytes) {
        return Base64Encoder.encode(bytes);
    }

    protected static byte[] base64Decode(String str) throws IOException {
        return Base64Decoder.decode(str);
    }


}
